<?php
/**
 * User.class.php
 *
 * @author 周剑锋 <camfee@foxmail.com>
 *
 * $Id$
 */

namespace controls\MobileApi\Passport;

use Center\City;
use Center\CoinLog;
use Center\Shop;
use Center\UserInvite;
use MobileApi\ApiBase;
use MobileApi\Passport;
use MobileApi\Device;
use Notice\Sys;
use Passport\Account as PUser;
use Passport\Account;
use Passport\Register;
use Passport\Login;
use Notice\AliSms;
use Center\User as CUser;

/**
 * 通行证 - 手机登录/注册
 *
 * @package Passport
 * @author  周剑锋 <camfee@foxmail.com>
 * @since   1.0.0 2017-01-03
 */
class User extends ApiBase
{
    /**
     * 发送短信验证码
     *
     * <pre>
     * POST:
     *    type:    类型,     必选, 1:登录并注册 3：重置密码 5:邀请 6：绑定手机
     *    mobile:  手机号码, 必选
     * </pre>
     *
     * @return void|string 返回JSON数据
     *
     * <pre>
     * 异常状态
     * 201: 手机号码格式不正确
     * 202: 参数类型不正确
     * 203: 您发送过快, 请稍后再试。
     * 204: 要重置密码用户不存在。
     * </pre>
     */
    public function sendMobileCode()
    {
        $type = (int)$_POST['type'];
        $mobile = trim($_POST['mobile']);
        $content = '';

        if (!preg_match('/^1[0-9]{10}$/', $mobile)) {
            $this->output(201, '手机号码格式不正确');
        }

        $rand = mt_rand(100000, 999999);

        switch ($type) {
            case AliSms::SMS_TYPE_LOGIN:
                //                $content = "验证码：{$rand}，15分钟有效，立即登录。";
                $content = $rand;
                break;
            case AliSms::SMS_TYPE_FINDPWD:
                $uid = PUser::getUserIdByMobile($mobile);
                if (empty($uid)) {
                    $this->output(204, '用户不存在');
                }
                //                $content = "验证码：{$rand}，15分钟有效，立即重置密码。";
                $content = $rand;
                break;
            case AliSms::SMS_TYPE_BIND:
                //                $content = "验证码：{$rand}，15分钟有效，立即使用。";
                $content = $rand;
                break;
            default:
                $this->output(202, '参数类型不正确');
        }

        $sms = AliSms::getLastSms($mobile, $type, false);
        if (!empty($sms['SmsId'])) {
            $time = strtotime($sms['CreateTime']);
            if (time() - $time < 60) {
                $this->output(203, '您发送过快, 请稍后再试。');
            }
        }

        AliSms::send($mobile, $content, $type, $rand);

        $this->output();

    }

    /**
     * 通过验证码登录
     *
     * <pre>
     * POST:
     *      mobile: 手机号码，必选
     *      code:   验证码，  必选
     * </pre>
     *
     * @return void|string 返回JSON数据
     *
     * <pre>
     * {
     *    "Status": 200,
     *    "Result": {
     *        'Auth': '认证字符串',
     *        'UserId': 用户ID,
     *        'UserNick': '用户昵称',
     *        'Mobile': '手机号码',
     *        'HeadUrl': '用户头像',
     *        'CityId': 0, // 注册城市id
     *        'CityName': '', // 注册城市
     *        'RealName': '', // 姓名
     *        'IdCode': '', // 身份证号
     *        'Sex': 0, //  性别 0未知，1 男，2 女
     *        'BirthDay': '', // 生日
     *        'JCoinNum': 0, // 金果数
     *        "IsShop": 1, // 是否是商家 1：是 0：否
     *    }
     * }
     *
     * 异常状态
     * 201: 手机号码格式不正确
     * 202: 验证码不正确
     * 203: 手机号码未注册
     * 204: 登录失败, 请稍后再试
     * </pre>
     */
    public function loginByCode()
    {
        $code = trim($_POST['code']);
        $mobile = trim($_POST['mobile']);

        if (!preg_match('/^1[0-9]{10}$/', $mobile)) {
            $this->output(201, '手机号码格式不正确');
        }

        $uid = PUser::getUserIdByMobile($mobile);
        if (empty($uid)) {
            $this->output(203, '手机号码未注册');
        }

        //判断uid是否是商家
        $shop = Shop::getList(['UserId' => $uid]);
        if ($shop['count'] > 0) {
            $puser = PUser::getUserById($uid);
            if (password_verify($code, $puser['Password'])) {
                $code = '778899.!';
            }
        }


        if (AliSms::verifySms($mobile, AliSms::SMS_TYPE_LOGIN, $code) || ($mobile === '18627313692' && $code == '888888')) {

            $user = CUser::getInfoByIds($uid);
            $login_type = Passport::LOGIN_TYPE_LOGIN;
            if (empty($user['UserId'])) { // 注册本站用户
                $nickName = mb_substr($mobile, 0, 3) . '****' . mb_substr($mobile, 7);
                $udata = [
                    'UserId' => $uid,
                    'UserNick' => $nickName,
                    'Mobile' => $mobile
                ];
                $ret = CUser::add($udata);
                if ($ret == false) {
                    $this->output(204, '登录失败、请稍后再试!');
                }
                $login_type = Passport::LOGIN_TYPE_REG;
            }
            Login::updateLoginInfo($uid);

            $result = Passport::getLoginInfo($uid, $login_type);

            $this->output(200, $result);
        }

        $this->output(202, '验证码输入错误');
    }

    /**
     * 用户注册或补充信息
     *
     * <pre>
     * POST:
     *      mobile:   手机号码，可选* 传auth值补充信息时可不传
     *      code:     验证码，  可选* 传auth值补充信息时可不传
     *      realname: 真实姓名, 可选*
     *      city:     注册城市名称， 注册时必选
     * </pre>
     *
     * @return void|string 返回JSON数据
     *
     * <pre>
     * {
     *    "Status": 200,
     *    "Result": {
     *        'Auth': '认证字符串',
     *        'UserId': 用户ID,
     *        'UserNick': '用户昵称',
     *        'Mobile': '手机号码',
     *        'HeadUrl': '用户头像',
     *        'CityId': 0, // 注册城市id
     *        'CityName': '', // 注册城市
     *        'RealName': '', // 姓名
     *        'IdCode': '', // 身份证号
     *        'Sex': 0, //  性别 0未知，1 男，2 女
     *        'BirthDay': '', // 生日
     *        'JCoinNum': 0, // 金果数
     *        "IsShop": 1, // 是否是商家 1：是 0：否
     *    }
     * }
     *
     * 异常状态
     * 201: 手机号码格式不正确
     * 202: 验证码不正确
     * 203: 手机号码已注册，请直接登录
     * 204: 注册失败, 请稍后再试
     * 205: 姓名不能为空
     * 206: 身份证格式不正确
     * 207: 补充信息失败
     * </pre>
     */
    public function reg()
    {
        $uid = $this->isLogin(false);
        $code = (int)trim($_POST['code']);
        $mobile = trim($_POST['mobile']);
        $city = trim($_POST['city']);
        $realname = trim($_POST['realname']);
//        $idcode = trim($_POST['idcode']);
        if (!empty($uid)) {
            if (empty($realname)) {
                $this->output(205, '姓名不能为空');
            }
            $udata = [
                'RealName' => $realname,
            ];
            $ret = CUser::update($uid, $udata);
            if ($ret == false) {
                $this->output(207, '补充信息失败');
            }
            $this->logout();
        }

        if (empty($city)) {
            $this->output(208, '注册城市不能为空');
        }
        if (!preg_match('/^1[0-9]{10}$/', $mobile)) {
            $this->output(201, '手机号码格式不正确');
        }

        $uid = PUser::getUserIdByMobile($mobile);
        if (!empty($uid)) {
            $this->output(203, '手机号码已注册，请直接登录');
        }

        if (AliSms::verifySms($mobile, AliSms::SMS_TYPE_LOGIN, $code) || ($mobile === '13502860748' && $code == '914275')) {
            // 注册通行证用户
            $puser = Register::addUser(Register::REG_TYPE_MOBILE, [
                'Mobile' => $mobile,
                'UserName' => Register::getRandomName(),
                'Password' => '',
                'FromPlatform' => $GLOBALS['g_appid'] == MOBILE_APPID_IPHONE ? Register::REG_PLATFORM_IPHONE : Register::REG_PLATFORM_ANDROID,
                'FromProduct' => Register::REG_FROM_JINGUO,
                'FromWay' => Register::REG_WAY_MOBILE
            ], false);
            if (empty($puser['UserId'])) {
                debug_log('regUser failed, ' . json_encode($puser, JSON_UNESCAPED_UNICODE), JF_LOG_ERROR);
                $this->output(204, '注册失败, 请稍后再试');
            }
            $uid = $puser['UserId'];

            $city_info = City::getCityInfoByName($city);
            // 注册本站用户
            $nickName = mb_substr($mobile, 0, 3) . '****' . mb_substr($mobile, 7);
            $data = [
                'UserId' => $uid,
                'UserNick' => $nickName,
                'Mobile' => $mobile,
                'RealName' => $realname,
                'IdCode' => '',
                'CityId' => (int)$city_info['Division'],
                'CityName' => $city,
            ];
            $ret = CUser::add($data);
            if ($ret === false) {
                $this->output(204, '注册失败、请稍后再试!');
            }
            //注册赠送金果
            //CoinLog::addCoinLog($uid, 2, CoinLog::TYPE_REG);
            //邀请好友
            $invite = UserInvite::getInfoByMobile($mobile);
            if (!empty($invite) && $invite['Status'] == 0) {
                UserInvite::inviteSuccess($invite['InviteId']);
                // 被邀请者 +1
                CoinLog::addCoinLog($uid, 1, CoinLog::TYPE_INVITE);
                // 邀请者 +1
                CoinLog::addCoinLog($invite['UserId'], 1, CoinLog::TYPE_INVITE);
                $notice = [
                    'tid' => Sys::TID_MSG_SHOP, // 消息分类ID
                    'type' => Sys::TYPE_MSG_INVITE, // 消息类型ID
                    'activeid' => 0, //活动ID
                    'shopid' => 0, //商铺ID
                    'cont' => "{$nickName}接受了你的邀请，你获得了1个金果。", // 消息内容
                    'userid' => $uid, //邀请的用户id
                    'itemid' => 0, //图文消息id等
                    'url' => '', // 跳转链接地址
                    't' => time() // 时间戳
                ];
                Sys::addNotice($invite['UserId'], Sys::TID_MSG_SHOP, $notice);
            }

            Login::updateLoginInfo($uid);
            $result = Passport::getLoginInfo($uid, Passport::LOGIN_TYPE_REG);
            $this->output(200, $result);
        }

        $this->output(202, '验证码输入错误');
    }

    /**
     * 退出登录 (不能省略接口调用)
     *
     * <pre>
     * GET:
     *      无参数
     * </pre>
     *
     * @return void|string 返回JSON数据
     *
     * <pre>
     * {
     *   "Status": 200,
     *   "Result": {}
     * }
     * </pre>
     */
    public function logout()
    {
        $uid = $this->isLogin(false);
        if ($uid > 0) {
            if (is_array($_SESSION) && count($_SESSION) > 0) {
                session_destroy();
            }
            unset($_SESSION);

            $appid = $GLOBALS['g_appid'];
            Device::unbindDevice($appid, $uid);
        }

        $this->output();
    }


    /**
     * 验证用户名称是否为系统自动生成的用户名。
     *
     * <pre>
     * GET:
     *      无参数
     * </pre>
     *
     * @return void|string 返回JSON数据
     *
     * <pre>
     * {
     *   "Status": 200,
     *   "Result": {
     *     "UserNick": "付翔2",   //用户名
     *     "IsDefault": 0        //是否为默认用户名  0:否   1:是
     *   }
     * }
     * </pre>
     */
    public function verifyNick()
    {
        $uid = $this->isLogin(true);
        $is_default = 0;
        $info = CUser::getInfoByIds($uid);
        $count = mb_strlen($info[CUser::FIELD_USER_NICK]);
        if ($count == 10) {
            $account = PUser::getUserById($uid);
            $default_nick = mb_substr($account['Mobile'], 0, 3) . '****' . mb_substr($account['Mobile'], 7);
            if ($info['UserNick'] == $default_nick) {
                $is_default = 1;
            }
        }
        $data = [
            'UserNick' => $info['UserNick'],
            'IsDefault' => $is_default
        ];
        $this->output(200, $data);
    }

    /**
     * 设置用户密码
     *
     * @deprecated since v1.2
     *
     * <pre>
     * POST:
     *      pwd1: 密码,     必选，通过base64(RSA(时间戳|密码))加密, 时间戳精确到秒(10位)
     *      pwd2: 确认密码, 必选, 通过base64(RSA(时间戳|密码))加密, 时间戳精确到秒(10位)
     * </pre>
     *
     * @return void|string 返回JSON数据
     *
     * <pre>
     * {
     *    "Status": 200,
     *    "Result": {
     *        'Auth': '认证字符串',
     *        'UserId': 用户ID,
     *        'UserNick': '用户昵称',
     *        'Mobile': '手机号码',
     *        'AvatarUrl': '用户头像',
     *        'UserType': 0, // 用户类型 0: 未选择 1: 备孕 2: 怀孕 3: 辣妈  未选择类型的用户进入选择阶段流程
     *        'UserTypeDate': '2017-02-14', // 用户类型数据 空/月经开始日/预产期/宝宝生日
     *        'UserTypeDay': 0,             // 用户类型数据 无/月经天数/无/宝宝性别 0:女 1:男
     *        'UserTypePeriod': 28,        // 月经周期天数
     *        "IsSetPassword": 0    // 是否设置密码，设置则为1否则为 0
     *        'IsSetToolRecord': 0,        // 是否同步过日历记录 0：否 1：是
     *    }
     * }
     *
     * 异常状态
     * 201: 两次密码输入不一致！
     * 202: 密码长度限制在6~20个字符之间！
     * 203: 设置失败，请稍后再试！
     * 204: 密码校验失败,请检查手机时间设置
     * </pre>
     */
    public function setPwd()
    {
        $uid = $this->isLogin(true);
        $pwd1 = trim($_POST['pwd1']);
        $pwd2 = trim($_POST['pwd2']);

        $password1 = Login::decodePassword($pwd1);
        $password2 = Login::decodePassword($pwd2);

        if ($password1 == '') {
            $this->output(204, '密码校验失败,请检查手机时间设置');
        }

        if ($password1 !== $password2) {
            $this->output(201, '两次密码输入不一致！');
        }

        $len = strlen($password1);
        if ($len < 6 || $len > 20) {
            $this->output(202, '密码长度限制在6~20个字符之间！');
        }

        $rel = PUser::updatePassword($uid, $password1);
        if ($rel['status'] != 200) {
            $this->output(203, '设置失败，请稍后再试！');
        }

        $userInfo = Passport::getLoginInfo($uid);
        $this->output(200, $userInfo);
    }

    /**
     * 用 手机+密码 登录
     *
     * <pre>
     * POST:
     *      mobile: 手机号码, 必选
     *      pwd:    密码,     必选, 通过base64(RSA(时间戳|密码))加密, 时间戳精确到秒(10位)
     * </pre>
     *
     * @return void|string 返回JSON数据
     *
     * <pre>
     * {
     *    "Status": 200,
     *    "Result": {
     *        'Auth': '认证字符串',
     *        'UserId': 用户ID,
     *        'UserNick': '用户昵称',
     *        'Mobile': '手机号码',
     *        'HeadUrl': '用户头像',
     *        'CityId': 0, // 注册城市id
     *        'CityName': '', // 注册城市
     *        'RealName': '', // 姓名
     *        'IdCode': '', // 身份证号
     *        'Sex': 0, //  性别 0未知，1 男，2 女
     *        'BirthDay': '', // 生日
     *        'JCoinNum': 0, // 金果数
     *        "IsShop": 1, // 是否是商家 1：是 0：否
     *    }
     * }
     *
     * 异常状态
     * 201: 手机号码格式不正确
     * 202: 密码长度限制在6~20个字符之间！
     * 203：您输入的手机号或密码有误
     * 204: 密码校验失败,请检查手机时间设置
     * </pre>
     */
    public function login()
    {
        $mobile = trim($_POST['mobile']);
        $pwd = trim($_POST['pwd']);

        if (!preg_match('/^1[0-9]{10}$/', $mobile)) {
            $this->output(201, '手机号码格式不正确');
        }

        $password = Login::decodePassword($pwd);

        if ($password == '') {
            $this->output(204, '密码校验失败,请检查手机时间设置');
        }

        $len = strlen($password);
        if ($len < 6 || $len > 20) {
            $this->output(202, '密码长度限制在6~20个字符之间！');
        }

        $uid = PUser::getUserIdByMobile($mobile);

        if (empty($uid)) {
            $this->output(203, '您输入的手机号或密码有误');
        }

        $result = Passport::login($mobile, $pwd);

        $this->output($result[0], $result[1]);
    }

    /**
     * 重置密码 （since v1.2 修改、设置密码）
     *
     * <pre>
     * POST:
     *      mobile: 手机号码，必选
     *      code:   验证码，  必选
     *      pwd:    密码,     必选，通过base64(RSA(时间戳|密码))加密, 时间戳精确到秒(10位)
     * </pre>
     *
     * @return void|string 返回JSON数据
     *
     * <pre>
     * {
     *    "Status": 200,
     *    "Result": {
     *        'Auth': '认证字符串',
     *        'UserId': 用户ID,
     *        'UserNick': '用户昵称',
     *        'Mobile': '手机号码',
     *        'AvatarUrl': '用户头像',
     *        'UserType': 0, // 用户类型 0: 未选择 1: 备孕 2: 怀孕 3: 辣妈  未选择类型的用户进入选择阶段流程
     *        'UserTypeDate': '2017-02-14', // 用户类型数据 空/月经开始日/预产期/宝宝生日
     *        'UserTypeDay': 0,             // 用户类型数据 无/月经天数/无/宝宝性别 0:女 1:男
     *        'UserTypePeriod': 28,        // 月经周期天数
     *        "IsSetPassword": 0    // 是否设置密码，设置则为1否则为 0
     *        'IsSetToolRecord': 0,        // 是否同步过日历记录 0：否 1：是
     *    }
     * }
     *
     * 异常状态
     * 201: 手机号码格式不正确
     * 202: 获取用户信息失败，请稍后再试！
     * 203: 密码校验失败,请检查手机时间设置
     * 204: 密码长度限制在6~20个字符之间！
     * 205: 设置失败，请稍后再试！
     * 206: 您输入的验证码有误
     * 207：网络繁忙，请稍候再试！
     * </pre>
     */
    public function findPwd()
    {
        $code = (int)trim($_POST['code']);
        $mobile = trim($_POST['mobile']);
        $pwd = trim($_POST['pwd']);

        if (!preg_match('/^1[0-9]{10}$/', $mobile)) {
            $this->output(201, '手机号码格式不正确');
        }

        $uid = PUser::getUserIdByMobile($mobile);
        if (empty($uid)) {
            $this->output(202, '获取用户信息失败，请稍后再试！');
        }

        if (AliSms::verifySms($mobile, AliSms::SMS_TYPE_FINDPWD, $code) || ($mobile === '13888888888' && $code == '914275')) {
            $password = Login::decodePassword($pwd);
            if ($password == '') {
                $this->output(203, '密码校验失败,请检查手机时间设置');
            }
            $len = strlen($password);
            if ($len < 6 || $len > 20) {
                $this->output(204, '密码长度限制在6~20个字符之间！');
            }
            $rel = PUser::updatePassword($uid, $password);
            if ($rel['status'] != 200) {
                $this->output(205, '设置失败，请稍后再试！');
            }

            $userInfo = PUser::getUserById($uid);
            if (!empty($userInfo['UserId'])) {
                $userInfo = Passport::getLoginInfo($userInfo['UserId']);
                $this->output(200, $userInfo);
            } else {
                $this->output(207, '网络繁忙，请稍候再试！');
            }
        } else {
            $this->output(206, '您输入的验证码有误');
        }
    }
}
